﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DAL;
using AutoMapper;
using RPXLib;
using RPXLib.Data;
using RPXLib.Interfaces;
using GrupyzServices.Logging;
using System.Web;
using System.Web.Security;

namespace GrupyzServices.BdAccess
{
    public class ClienteRepository : IClienteRepository
    {

        GrupyzEntities _entity;
        ILogger log;

        public ClienteRepository()
        {
            _entity = new GrupyzEntities();
            log = new NLogLogger();
        }

        public IEnumerable<Cliente> GetClientes()
        {
            throw new NotImplementedException();
        }

        public Cliente GetClienteById(int id)
        {
            return (from x in _entity.Cliente
                    where x.Id == id
                    select x).SingleOrDefault();
        }

        public string GetReferencia(int idCliente)
        {
            try
            {
                return GetClienteById(idCliente).Referencia;
            }
            catch (Exception)
            {
                return "";
            }

        }

        public Cliente GetClienteByIdSocial(string idSocial,string email)
        {
            try
            {
                return (from x in _entity.Cliente
                        where x.IDSocial == idSocial
                        || x.Email == email
                        select x).SingleOrDefault();
            }
            catch (InvalidOperationException ex)
            {
                log.Error(ex);
                return null;
            }


        }

        public DadosCliente GetDadosCliente(int id)
        {
            OrderRepository rep = new OrderRepository();
            bool comprou = rep.ClienteJaComprou(id);

            return (from x in _entity.Cliente
                    where x.Id == id
                    select new DadosCliente
                    {
                        Id = x.Id,
                        Nome = x.Nome,
                        DataNascimento = x.DataNascimento,
                        Sexo = x.Sexo,
                        Email = x.Email,
                        Localidade = x.Localidade,
                        CodPostal = x.CodPostal,
                        Morada = x.Morada,
                        Telefone = x.Telefone,
                        TornarSocial = x.TornarSocial,
                        MostraSocial = x.IDSocial == "offline" && x.Password != null,
                        jaDefiniuPass = x.IDSocial != "offline" && x.Password != null,
                        Referencia = comprou ? "http://tinyurl.com/34c6bmg/" + x.Referencia : ""
                    }).SingleOrDefault();
        }

        public LoginHeader GetLoginHeader(string id)
        {
            int Id =0;
            int.TryParse(id, out Id);

            return (from x in _entity.Cliente.Include("Pontos")
                    where x.Id == Id
                    select new LoginHeader
                     {
                         Nome = "Olá, " + x.Nome,
                         UriImagem = x.UriImagem,
                         Pontos = x.Ponto.FirstOrDefault().Pontos == null ? 0 : x.Ponto.FirstOrDefault().Pontos
                     }).SingleOrDefault();
        }

        public bool UpdateCliente(DadosCliente SrcCliente, int DestClienteID)
        {
            try
            {
                if (GetClienteByEmail(SrcCliente.Email,SrcCliente.Id) != null) return false;

                Cliente cli = GetClienteById(DestClienteID);

                if (cli.Email != SrcCliente.Email) 
                { 
                    if (cli.Email != null)
                        UpdateTemNewsletter(cli.Email, false);
                    else
                        UpdateTemNewsletter(SrcCliente.Email, true);
                }

                //if (!string.IsNullOrEmpty(SrcCliente.Password))
                //    SrcCliente.Password = FormsAuthentication.HashPasswordForStoringInConfigFile(SrcCliente.Password, "MD5");

                //Mapper.CreateMap<DadosCliente, Cliente>();
                //Mapper.Map(SrcCliente, cli);

                cli.CodPostal = SrcCliente.CodPostal;
                cli.DataNascimento = SrcCliente.DataNascimento;
                cli.DisplayName = SrcCliente.Nome;
                cli.Email = SrcCliente.Email;
                cli.Localidade = SrcCliente.Localidade;
                cli.Morada = SrcCliente.Morada;
                cli.Nome = SrcCliente.Nome;
                if (!string.IsNullOrEmpty(SrcCliente.Password))
                    cli.Password = FormsAuthentication.HashPasswordForStoringInConfigFile(SrcCliente.Password, "MD5");
                cli.Sexo = SrcCliente.Sexo;
                cli.Telefone = SrcCliente.Telefone;
                cli.TornarSocial = SrcCliente.TornarSocial;


                _entity.SaveChanges();

                return true;
            }
            catch (Exception ex)
            {
                log.Error(ex);
                return false;
            }
        }

        public int InsertCliente(string userName, string password, string email)
        {
            try
            {
                var cli = GetClienteByEmail(email);
                if (cli != null) { return 7; }

                Cliente cliente = new Cliente();
                cliente.Nome = userName;
                cliente.Email = email;
                cliente.Password = password;
                cliente.Referencia = Guid.NewGuid().ToString().Replace("-", "");
                cliente.UriImagem = "~/Content/images/ecyu2wwn.gif";
                cliente.IDSocial = "offline";
                cliente.DisplayName = userName;

                _entity.Cliente.AddObject(cliente);
                cliente.Settings.Add(new Settings());
                _entity.SaveChanges();

                HttpContext.Current.Session["idUser"] = cliente.Id;
                UpdateTemNewsletter(cliente.Email, true);

                //MailTools.Mail.Registo(cliente.Email);

                return 0;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                return 11;
            }
        }


        public Cliente InsertClienteRPX(RPXAuthenticationDetails authenticationDetails)
        {
            try
            {
                Cliente cliente = new Cliente();
                DateTime dt;
                cliente.IDSocial = authenticationDetails.Identifier;
                cliente.Nome = authenticationDetails.Name.Formatted;
                if (authenticationDetails.Gender != null)
                    cliente.Sexo = authenticationDetails.Gender.ToUpper() == "MALE" ? "M" : "F";
                cliente.DisplayName = authenticationDetails.PreferredUsername;
                if (authenticationDetails.Birthday != null && DateTime.TryParse(authenticationDetails.Birthday, out dt))
                {
                    cliente.DataNascimento = dt;
                }
                cliente.Referencia = Guid.NewGuid().ToString().Replace("-", "");
                cliente.UriImagem = authenticationDetails.PhotoUrl ?? "~/Content/images/ecyu2wwn.gif";
                cliente.Email = authenticationDetails.VerifiedEmail ?? authenticationDetails.Email;
                cliente.Localidade = authenticationDetails.Address.Region;
                cliente.Telefone = authenticationDetails.PhoneNumber;

                if (cliente.Email != null) UpdateTemNewsletter(cliente.Email, true);

                _entity.Cliente.AddObject(cliente);

                cliente.Settings.Add(new Settings());
                
                _entity.SaveChanges();

                MailTools.Mail.Registo(cliente.Email);

                return cliente;
            }
            catch (Exception ex)
            {
                log.Error(ex);
                return null;
            }
        }


        public void UpdateTemNewsletter(string email, bool Activamail)
        {
            try
            {
                EnvioNewsletter news = (from x in _entity.EnvioNewsletter
                                        where x.Email == email
                                        select x).Single();
                if (!Activamail)
                    _entity.EnvioNewsletter.DeleteObject(news);
            }
            catch (Exception)
            {
                if (Activamail)
                    _entity.EnvioNewsletter.AddObject(new EnvioNewsletter { Email = email });
            }

            _entity.SaveChanges();
        }


        public Cliente GetClienteByEmail(string email, int id)
        {
            return (from x in _entity.Cliente
                    where x.Email == email
                    && x.Id != id
                    select x).SingleOrDefault();
        }


        public Cliente GetClienteByEmailSocial(string email, string idSocial)
        {
            return (from x in _entity.Cliente
                    where x.Email == email
                    && x.IDSocial != idSocial
                    select x).SingleOrDefault();
        }


        public  SettingsViewModel GetClienteSettings(int idCliente)
        {
            var settings = (from x in _entity.Settings
                           where x.ClienteId == idCliente
                           select x).SingleOrDefault();

            return (from x in _entity.Cliente
                    join o in _entity.EnvioNewsletter on x.Email equals o.Email into g
                    from o in g.DefaultIfEmpty()
                    where x.Id == idCliente
                    select new SettingsViewModel {
                    ClienteId = idCliente,
                    DealExpire = settings.DealExpire,
                    FriendReferenced = settings.FriendReferenced,
                    PremioAdicionado = settings.PremioAdicionado,
                    TemNewsLetter = o == null ? false : true
                    }).SingleOrDefault();
        }

        public PremiosViewModel GetClientePremios(int idCliente)
        {
            
             var model = (from x in _entity.Cliente.Include("Premios.TipoPremio")
                    where x.Id == idCliente
                    select x).SingleOrDefault().Premios.SingleOrDefault();

             if (model == null) return null;

            return new PremiosViewModel { 
                Descricao = model.Descricao,
                Valor = model.Valor,
                Data = model.Data,
                Activo = model.Activo,
                TipoPremio = model.TipoPremio.Nome
             };
        }


        public IEnumerable<ClienteComprasViewModel> GetComprasCliente(int idCliente)
        {
            OrderRepository orderRep = new OrderRepository();
            return orderRep.GetOrdersCliente(idCliente);
        }


        public bool UpdateSettings(SettingsViewModel settings)
        {
            try
            {
                var set = (from c in _entity.Settings
                          where c.ClienteId == settings.ClienteId
                          select c).SingleOrDefault();

                string email = (from x in _entity.Cliente
                            where x.Id == settings.ClienteId
                            select x.Email).SingleOrDefault();

                Mapper.CreateMap<SettingsViewModel, Settings>();
                Mapper.Map(settings, set);

                //_entity.Settings.Attach(settings);
                //_entity.ObjectStateManager.ChangeObjectState(settings, System.Data.EntityState.Modified);
                
                
                _entity.SaveChanges();

                UpdateTemNewsletter(email, settings.TemNewsLetter);

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }


        public void UpdateClienteOrder(DAL.Order order, int userId)
        {
            try
            {
                var cli = GetClienteById(userId);

                cli.Nome = order.PrimeiroNome + " " + order.UltimoNome;
                cli.Morada = order.Morada;
                cli.CodPostal = order.CodPostal;
                cli.Localidade = order.Localidade;
                cli.Telefone = order.Telefone;
                //cli.Email = cli.Email;
                _entity.SaveChanges();
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }


        public bool UpdatePontos(int idCliente, bool Adiciona, int pontos = 1)
        {
            try
            {
                var cli =(from x in _entity.Cliente.Include("Ponto")
                          where x.Id == idCliente
                          select x).SingleOrDefault();


                if (cli.Ponto.FirstOrDefault() == null)
                {
                    Ponto p = new Ponto();
                    p.Pontos = pontos;
                    cli.Ponto.Add(p);
                }
                else
                {
                    if(Adiciona)
                        cli.Ponto.FirstOrDefault().Pontos += pontos;
                    else
                        cli.Ponto.FirstOrDefault().Pontos -= pontos;
                }

                _entity.SaveChanges();

                return true;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                return false;
            }
        }


        public Cliente GetClienteByEmail(string email)
        {
            return (from x in _entity.Cliente
                    where x.Email == email
                    select x).SingleOrDefault();
        }


        public bool ValidateCliente(string email, string password)
        {
            try
            {
                var cli = (from x in _entity.Cliente
                           where x.Email == email
                           && x.Password == password
                           select x).SingleOrDefault();

                if (cli != null)
                {
                    HttpContext.Current.Session["idUser"] = cli.Id;
                    return true;
                }
                else
                    return false;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                return false;
            }

        }


        public int MigrarClienteSocial(RPXAuthenticationDetails authenticationDetails)
        {
            try
            {
                var cliente = GetClienteByEmail(authenticationDetails.VerifiedEmail == null ? authenticationDetails.Email : authenticationDetails.VerifiedEmail);

                DateTime dt;
                cliente.IDSocial = authenticationDetails.Identifier;
                cliente.Nome = authenticationDetails.Name.Formatted;
                if (authenticationDetails.Gender != null)
                    cliente.Sexo = authenticationDetails.Gender.ToUpper() == "MALE" ? "M" : "F";
                //cliente.DisplayName = authenticationDetails.PreferredUsername;
                cliente.DisplayName = authenticationDetails.Name.Formatted;
                if (authenticationDetails.Birthday != null && DateTime.TryParse(authenticationDetails.Birthday, out dt))
                {
                    cliente.DataNascimento = dt;
                }
                cliente.Referencia = Guid.NewGuid().ToString().Replace("-", "");
                cliente.UriImagem = authenticationDetails.PhotoUrl ?? "~/Content/images/ecyu2wwn.gif";
                cliente.Email = authenticationDetails.VerifiedEmail ?? authenticationDetails.Email;
                cliente.Localidade = authenticationDetails.Address.Formatted;
                cliente.Telefone = authenticationDetails.PhoneNumber;

                _entity.SaveChanges();

                return cliente.Id;
            }
            catch (Exception)
            {
                return 0;
                throw;
            } 

        }

        public void ResetPassword(string email)
        {
            try
            {
                var cli = GetClienteByEmail(email);
                string pass = GeneratePassword();
                MailTools.Mail.EsqueceuPassword(email, pass);
                cli.Password = FormsAuthentication.HashPasswordForStoringInConfigFile(pass,"MD5");

                _entity.SaveChanges();
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }

        }

        private string GeneratePassword()
        {
            Random rGen = new Random();
            string[] strCharacters = { "A","B","C","D","E","F","G",
            "H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y",
            "Z","1","2","3","4","5","6","7","8","9","0","a","b","c","d","e","f","g","h",
            "i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};

            int p = 0;
            string strPass = "";
            for (int x = 0; x <= 10; x++)
            {
                p = rGen.Next(0, 60);
                strPass += strCharacters[p];
            }
            return strPass;
        }


        public bool ChangePassword(int idUser, string oldPassword, string newPassword)
        {
            try
            {
                var cli = GetClienteById(idUser);
                if (cli.Password == FormsAuthentication.HashPasswordForStoringInConfigFile(oldPassword, "MD5"))
                {
                    cli.Password = FormsAuthentication.HashPasswordForStoringInConfigFile(newPassword,"MD5");
                    _entity.SaveChanges();
                    return true;
                }
                else return false;

            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                return false;
            }

        
        }


        public List<int> GetPontosCliente(int idCliente)
        {
            try
            {
                int pontos = (from x in _entity.Cliente.Include("Ponto")
                              where x.Id == idCliente
                              select x.Ponto.FirstOrDefault().Pontos).SingleOrDefault();

                if (pontos > 5) pontos = 5;

                return (from p in Enumerable.Range(0, pontos + 1)
                        select p).ToList();
            }
            catch (Exception)
            {
                return new List<int> { 0 };
            }
        }

        public bool UpdateOrderPontos(int idCliente, int pontos)
        {
            throw new NotImplementedException();
        }


        public bool UpdateReferencias(int idCliente, decimal? valor,bool jaComprou, bool negocioConcluido)
        {
            try
            {
                //se tem cookie e ainda nao comprou
                if (HttpContext.Current.Request.Cookies["Referencia"] != null && !jaComprou)
                {
                    Cliente cli = GetClienteByReferencia(HttpContext.Current.Request.Cookies["Referencia"].Value);
                    int idRef = cli.Id;
                    
                    var refer = from x in _entity.Referencia
                                where x.IdClienteReferencia == idCliente
                                select x;

                    foreach (var item in refer)
                    {
                        _entity.Referencia.DeleteObject(item);
                        _entity.SaveChanges();
                    }
                   
                    Referencia refr = new Referencia();
                    refr.Activo = true;
                    refr.Data = DateTime.Now;
                    refr.DataLimite = DateTime.Now.AddHours(72);
                    refr.IdClienteReferencia = idCliente;
                    refr.IdClienteReferenciado = idRef;
                    refr.Valor = decimal.Parse(valor.ToString());

                    _entity.Referencia.AddObject(refr);
                    _entity.SaveChanges();

                    var total = (from x in _entity.Referencia
                        where x.IdClienteReferenciado == idRef
                        select x).Count();

                    var settings = (from x in _entity.Settings
                                    where x.ClienteId == idCliente
                                    select x).SingleOrDefault();

                    if (negocioConcluido)
                    {
                        UpdatePontos(idRef, true, 5);

                        //update aos pontos = 5 se 5 pessoas ja compraram 
                        if (total == 5) UpdatePontos(idRef, true, int.Parse(valor.ToString()));

                        //Se tiver alerta envia o mail a informar a compra da referencia
                        if (settings.FriendReferenced)
                            MailTools.Mail.AlertarCompraReferencia(cli.Email, GetClienteById(idCliente).Nome, total);
                    }
                    else
                    { 
                        //Se tiver alerta envia o mail a informar a compra pendente da referencia
                        if (settings.FriendReferenced)
                            MailTools.Mail.AlertarCompraReferenciaPendente(cli.Email, GetClienteById(idCliente).Nome, total);
                    }

                    return true;
                }
                else return false;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                return false;
            }
        }


        public Cliente GetClienteByReferencia(string referencia)
        {
            return (from x in _entity.Cliente
                   where x.Referencia == referencia
                   select x).SingleOrDefault();
        }
    }
}
